<?php

namespace Zeke\Net\Http;

use Psr\Http\Message\UriInterface;
use Psr\Http\Message\StreamInterface;
use RingCentral\Psr7\Request as g7Request;
use Psr\Http\Message\ServerRequestInterface;

/**
 * [Internal] Implementation of the PSR-7 `ServerRequestInterface`
 *
 * This is used internally to represent each incoming request message.
 *
 * This implementation builds on top of an existing outgoing request message and
 * only adds required server methods.
 *
 * Note that this is an internal class only and nothing you should usually care
 * about. See the `ServerRequestInterface` for more details.
 *
 * @see ServerRequestInterface
 */
class Request extends g7Request implements ServerRequestInterface
{

    /**
     * @var array
     */
    private $attributes = array();

    /**
     * @var array
     */
    private $serverParams;

    /**
     * @var array
     */
    private $fileParams = array();

    /**
     * @var array
     */
    private $cookies = array();

    /**
     * @var array
     */
    private $queryParams = array();

    /**
     * @var
     */
    private $parsedBody;



    /**
     * @param null|string $method HTTP method for the request.
     * @param null|string|UriInterface $uri URI for the request.
     * @param array $headers Headers for the message.
     * @param string|resource|StreamInterface $body Message body.
     * @param string $protocolVersion HTTP protocol version.
     * @param array $serverParams server-side parameters
     *
     * @throws \InvalidArgumentException for an invalid URI
     */
    public function __construct($method, $uri, $headers = array(), $body = null, $protocolVersion = '1.1', $serverParams = array())
    {
        $this->serverParams = $serverParams;
        parent::__construct($method, $uri, $headers, $body, $protocolVersion);
    }


    /**
     * 请求参数
     *
     * @return array
     *
     * @author <liu.bin@ruaby.com> 2018-08-22 14:00
     */
    public function getServerParams()
    {
        return $this->serverParams;
    }


    /**
     * cookie
     *
     * @return array
     *
     * @author <liu.bin@ruaby.com> 2018-08-22 14:00
     */
    public function getCookieParams()
    {
        return $this->cookies;
    }

    /**
     * 设置cookie
     *
     * @param array $cookies
     * @return Request|static
     *
     * @author <liu.bin@ruaby.com> 2018-08-22 14:00
     */
    public function withCookieParams(array $cookies)
    {
        $new = clone $this;
        $new->cookies = $cookies;
        return $new;
    }


    /**
     * url参数
     *
     * @return array
     *
     * @author <liu.bin@ruaby.com> 2018-08-22 14:00
     */
    public function getQueryParams()
    {
        return $this->queryParams;
    }

    /**
     * 设置url参数
     *
     * @param array $query
     * @return Request|static
     *
     * @author <liu.bin@ruaby.com> 2018-08-22 14:01
     */
    public function withQueryParams(array $query)
    {
        $new = clone $this;
        $new->queryParams = $query;
        return $new;
    }

    /**
     * 获取上传文件
     *
     * @return array
     *
     * @author <liu.bin@ruaby.com> 2018-08-22 14:01
     */
    public function getUploadedFiles()
    {
        return $this->fileParams;
    }


    /**
     * 设置上传文件
     *
     * @param array $uploadedFiles
     * @return Request|static
     *
     * @author <liu.bin@ruaby.com> 2018-08-22 14:01
     */
    public function withUploadedFiles(array $uploadedFiles)
    {
        $new = clone $this;
        $new->fileParams = $uploadedFiles;
        return $new;
    }


    /**
     * 消息体
     *
     * @return array|null|object
     *
     * @author <liu.bin@ruaby.com> 2018-08-22 14:02
     */
    public function getParsedBody()
    {
        return $this->parsedBody;
    }


    /**
     * 设置消息体
     *
     * @param array|null|object $data
     * @return Request|static
     *
     * @author <liu.bin@ruaby.com> 2018-08-22 14:02
     */
    public function withParsedBody($data)
    {
        $new = clone $this;
        $new->parsedBody = $data;
        return $new;
    }

    /**
     * 获取所有Attributes
     *
     * @return array
     *
     * @author <liu.bin@ruaby.com> 2018-08-22 14:02
     */
    public function getAttributes()
    {
        return $this->attributes;
    }


    /**
     * 获取指定Attribute
     *
     * @param string $name
     * @param null $default
     * @return mixed|null
     *
     * @author <liu.bin@ruaby.com> 2018-08-22 14:53
     */
    public function getAttribute($name, $default = null)
    {
        if (!array_key_exists($name, $this->attributes)) {
            return $default;
        }
        return $this->attributes[$name];
    }

    /**
     * 设置指定Attribute
     *
     * @param string $name
     * @param mixed $value
     * @return Request|static
     *
     * @author <liu.bin@ruaby.com> 2018-08-22 14:53
     */
    public function withAttribute($name, $value)
    {
        $new = clone $this;
        $new->attributes[$name] = $value;
        return $new;
    }

    /**
     * 清除指定Attribute
     *
     * @param string $name
     * @return Request|static
     *
     * @author <liu.bin@ruaby.com> 2018-08-22 14:55
     */
    public function withoutAttribute($name)
    {
        $new = clone $this;
        unset($new->attributes[$name]);
        return $new;
    }


    /**
     * 解析cookie
     *
     * @internal
     * @param string $cookie
     * @return boolean|mixed[]
     */
    public static function parseCookie($cookie)
    {
        // PSR-7 `getHeaderLine('Cookies')` will return multiple
        // cookie header comma-seperated. Multiple cookie headers
        // are not allowed according to https://tools.ietf.org/html/rfc6265#section-5.4
        if (strpos($cookie, ',') !== false) {
            return false;
        }

        //按照;分割
        $cookieArray = explode(';', $cookie);
        $result = array();

        foreach ($cookieArray as $pair) {
            $pair = trim($pair);
            $nameValuePair = explode('=', $pair, 2);

            if (count($nameValuePair) === 2) {
                $key = urldecode($nameValuePair[0]);
                $value = urldecode($nameValuePair[1]);
                $result[$key] = $value;
            }
        }

        return $result;
    }
}
